Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bluetooth Device Pairing Infrastructure and Health Measurements #1

Merged
merged 77 commits into from
Jul 2, 2024

Conversation

Supereg
Copy link
Member

@Supereg Supereg commented Jun 9, 2024

Bluetooth Device Pairing Infrastructure and Health Measurements

♻️ Current situation & Problem

This is the initial PR for SpeziDevices. It introduces three targets SpeziDevices, SpeziDevicesUI and SpeziOmron.

SpeziDevices provides device pairing and health measurements functionality for BluetoothDevices implemented using SpeziBluetooth. SpeziDevicesUI provides UI components on top of that, e.g., visualizing paired devices, editing their information, showing nearby pairable devices, showing new health measurements, etc.
SpeziOmron provides reusable implementations of Omron Bluetooth peripherals like the SC150 weight scale and the BP5250 blood pressure cuff.

⚙️ Release Notes

  • Introduce PairedDevices module to manage paired devices. Discovering, pairing and connecting to them.
  • Introduce HealthMeasurements to manage health measurements from Bluetooth Devices and converting them to HealthKit samples.
  • Introduce SpeziOmron with reusable Omron device implementations.

📚 Documentation

All targets contain DocC catalogs, documenting all their types.

✅ Testing

This PR adds extensive unit testing of components and has an UI Test app to test UI components.

📝 Code of Conduct & Contributing Guidelines

By submitting creating this pull request, you agree to follow our Code of Conduct and Contributing Guidelines:

Supereg added a commit to StanfordSpezi/SpeziBluetooth that referenced this pull request Jun 10, 2024
…trol Point (#29)

# Support Control Point Characteristics and implement Record Access
Control Point

## ♻️ Current situation & Problem
The Record Access Control Point characteristic is a standardized
Bluetooth characteristic to model service-specific procedures for
management of a set of data records. While the exact format is specific
to the service specification using it, both the Glucose Monitor service
and Enhanced Blood Pressure service define a similar format for the
Record Access Control Point characteristic. Similar, Omron defines a
custom service for their Blood Pressure Cuffs with a similar
implementation of the Record Access Control Point characteristic.
This PR implements a Record Access Control Point characteristic that is
generic an can be instantiated with the respective service
specification. Further, it instantiates it using the `GenericOperand`
that is common to services like the Glucose Monitor and the Enhanced
Blood Pressure service. An instantiation of the Omron option service is
done in StanfordSpezi/SpeziDevices#1.

To better support control point characteristics, this PR also adds a new
`ControlPointCharacteristic` marker protocol that allows to access
native support to sending requests and receiving the response to and
from a control point characteristic (one async call instead of writing a
value and waiting for the notification).

## ⚙️ Release Notes 
* Add new `ControlPointCharacteristic` marker protocol and a
`sendRequest(_:timeout:)` accessor.
* Add support for the `RecordAccessControlPoint` characteristic.


## 📚 Documentation
Documentation catalog was updated to include those new symbols and new
symbols were documented accordingly.

## ✅ Testing
The new characteristic was fully unit tested. We added additional
support within the `TestingSupport` SPI to make unit testing of control
point characteristics easier.
Functionality was validated against a Omron Bluetooth device for
real-world testing.


## 📝 Code of Conduct & Contributing Guidelines 

By submitting creating this pull request, you agree to follow our [Code
of
Conduct](https://github.com/StanfordSpezi/.github/blob/main/CODE_OF_CONDUCT.md)
and [Contributing
Guidelines](https://github.com/StanfordSpezi/.github/blob/main/CONTRIBUTING.md):
- [x] I agree to follow the [Code of
Conduct](https://github.com/StanfordSpezi/.github/blob/main/CODE_OF_CONDUCT.md)
and [Contributing
Guidelines](https://github.com/StanfordSpezi/.github/blob/main/CONTRIBUTING.md).
Supereg added a commit to StanfordSpezi/SpeziBluetooth that referenced this pull request Jun 27, 2024
# Support retrieving Peripherals

## ♻️ Current situation & Problem

SpeziBluetooth is currently optimized for device discovery and ad-hoc
connection establishment. However, when dealing with device pairing, one
typically scans for nearby devices once and saving the peripheral
identifier and perform long running connection attempts (e.g., calling
[`retrievePeripherals(withidentifiers:)`](https://developer.apple.com/documentation/corebluetooth/cbcentralmanager/retrieveperipherals(withidentifiers:))
and calling connect()). Connecting a peripheral does not time out and is
therefore the most efficient way of establishing Bluetooth connecting
with a set of known Bluetooth devices.
To support this use case, some modifications have been made to the
underlying SpeziBluetooth infrastructure. New mechanisms were introduced
to retrieve known peripherals
(`BluetoothManager/retrievePeripheral(for:with:)` and
`Bluetooth/retrieveDevice(for:as:)`). These device instances can stay
allocated and SpeziBluetooth automatically frees resources once the
framework user deallocates the peripheral instances. Several changes to
the lifecycle handling of `BluetoothPeripheral`s and `BluetoothDevice`s
have been made to support this new interfaces (e.g., carefully managing
when objects are kept as strong references and when to reuse objects
when, e.g., the same instance is getting discovered at the same time).

### SpeziDevices

SpeziDevices is an upcoming library to encapsulates a lot of
standardized device interactions. This PR is driven by a lot of
requirements of this library.

## :gear: Release Notes 

* Support retrieving known peripherals using
`BluetoothManager/retrievePeripheral(for:with:)` and
`Bluetooth/retrieveDevice(for:as:)`.
* The `BluetoothViews` target was removed and integrated into the
`SpeziDevicesUI` of the SpezIDevices framework (see
StanfordSpezi/SpeziDevices#1, **Breaking**).
* The `BluetoothServices` target was renamed to `SpeziBluetoothServices`
for more consistency (**Breaking**).
* Add `accessory` discovery criteria.
* New `nearby` and `lastActivity` state properties for peripherals and
devices.
* The peripheral name is now preferred with the `name` property and the
`localName` property can now be accessed individually on a peripheral
(**Breaking**).
* Internally restructure discovery state into an `DiscoverySession` for
better code overview.
* Configuration options (like minimumRSSI and
advertisementStaleInterval) are now passed directly to the
`scanNearbyDevices(...)` methods and modifiers allowing for more dynamic
configuration.
* Adding `Bluetooth/stateSubscription` and
`BluetoothManager/stateSubscription` to receive an AsyncStream of
`BluetoothState` changes useful when required to observe CBCentral
changes.
* Adding `CharacteristicAccessor/subscription` and
`DeviceStateAccessor/subscription` properties to receive an AsyncStream
of changes to the characteristic value or device state.
* `onChange(initial:perform:)` methods now must not be set up in the
initializer anymore and must not create strong self references. Instead
setup onChange handlers in the `configure()` method and make sure to
weakly capture `self`. Calling `onChange(initial:perform:)` method in
the initializer results in a runtime crash with the error message
providing a migration guide.
* New `powerOn()` and `powerOff()` methods to manually control
`CBCentralManager` allocation.
* Fixed an issue where characteristic access continuations where
accidentally leaked.
* Add new `ManufacturerIdentifier` model supporting parsing of
manufacturer data in the advertisement.
* Added `ConnectedDevices` environment model to retrieve all connected
devices from the SwiftUI environment.
* Add `Codable` conformance to all Characteristics.

This PR contains breaking changes, requiring a major version bump.

## :books: Documentation
Documentation was updated to reflect changed symbols (README currently
points to 404 pages). Retrieving devices was documented with a small
code examples.


## :white_check_mark: Testing
Existing tests verify that refactoring did not break existing
infrastructure. Additional test case was added to test retrieving
peripherals and ensuring the new reference semantics do not break and
peripherals are properly and expectedly deallocated.


## :pencil: Code of Conduct & Contributing Guidelines 

By submitting creating this pull request, you agree to follow our [Code
of
Conduct](https://github.com/StanfordSpezi/.github/blob/main/CODE_OF_CONDUCT.md)
and [Contributing
Guidelines](https://github.com/StanfordSpezi/.github/blob/main/CONTRIBUTING.md):
- [x] I agree to follow the [Code of
Conduct](https://github.com/StanfordSpezi/.github/blob/main/CODE_OF_CONDUCT.md)
and [Contributing
Guidelines](https://github.com/StanfordSpezi/.github/blob/main/CONTRIBUTING.md).
@PSchmiedmayer PSchmiedmayer self-requested a review June 27, 2024 20:50
@PSchmiedmayer PSchmiedmayer added the enhancement New feature or request label Jun 27, 2024
Copy link
Member

@PSchmiedmayer PSchmiedmayer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice work with the PR @Supereg!

Those are some great additions to the ecosystem. I had a few comments here and there but nothing major.

Main elements that might be high-level are:

  1. Identify if we have some "dead" code somewhere here in the package that we might want to remove before merging it. Some of the record access part might be strategically left in there for now as we aim to support this in the future.
  2. Identify where and how we want to use Swift Data for the elements here. As discussed in Slack, we might want to keep it for the required persistence layers but exploring the other options would be great if it stays within our available time.

Overall: Great work, excited to see this being integrated in a lot of apps!

.spi.yml Outdated Show resolved Hide resolved
CITATION.cff Show resolved Hide resolved
README.md Outdated Show resolved Hide resolved
Sources/SpeziDevicesUI/Devices/DevicesGrid.swift Outdated Show resolved Hide resolved
Sources/SpeziDevicesUI/Devices/DevicesTab.swift Outdated Show resolved Hide resolved
Sources/SpeziDevicesUI/Utils/CarouselDots.swift Outdated Show resolved Hide resolved
Sources/SpeziDevicesUI/Utils/PaneContent.swift Outdated Show resolved Hide resolved
Sources/SpeziOmron/SpeziOmron.docc/SpeziOmron.md Outdated Show resolved Hide resolved
@Supereg Supereg marked this pull request as ready for review July 1, 2024 10:40
Copy link
Member

@PSchmiedmayer PSchmiedmayer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for the work here @Supereg!

Would be great if we can add some screenshots to the README & module documentations to provide some visual examples what is possible with this package.

Once the TODOs and PR checks are resolved I would be happy to see this PR merged; we can then provide follow-up improvements and other elements as we tag newer versions 🚀

@Supereg
Copy link
Member Author

Supereg commented Jul 2, 2024

As discussed, we will tackle all README changes in a follow-up PR. Tracked via #2

@Supereg
Copy link
Member Author

Supereg commented Jul 2, 2024

Moving some views to SpeziViews is tracked here StanfordSpezi/SpeziViews#40

@Supereg Supereg merged commit 6b5e24f into main Jul 2, 2024
9 checks passed
@Supereg Supereg deleted the feature/initial-project-setup branch July 2, 2024 17:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
Archived in project
Development

Successfully merging this pull request may close these issues.

2 participants